import random
import logging
import snakemq.link as slink
import snakemq.packeter as spacketer
import snakemq.messaging as smessaging
import snakemq.message as smessage
import threading
import datetime
import time
import json

# Sensor
# Simulates sensor hardware.
class Sensor(object):

	_id_prefix = "SENSOR"

	def __init__(self, sensor_id, low, high):
		self.id = self._id_prefix + "_" + sensor_id
		self.low = low
		self.high = high
		random.seed()

	def read(self):
		return random.normalvariate(100,10)

# Converter
# Convert a sensor's raw data into 
# a configured format.
class Converter(object):
	
	def __init__(self):
		self.sensor_rates = {}

	def configure_sensor(self, sensor, rate):
		self.sensor_rates[sensor.id] = rate

	def convert(self, sensor):
		raw = sensor.read()
		if sensor.id not in self.sensor_rates:
			return raw
		else:
			# perform some mathematical operation here
			# to convert to whatever rate would be desired,
			# exact algorithm is not pertinent for the example implementation.
			return raw * self.sensor_rates[sensor.id]

# DataCollector
#
# Read sensors and dispatch vital signs to
# subscribers, namely the VitalsBuffer and AlarmChecker.
class DataCollector(object):

	_id_prefix = "COLLECTOR"
	
	def __init__(self, id, num_sensors, host="localhost"):
		self.id = self._id_prefix + "_" + str(id)
		self.sensors = []
		self.converter = Converter()
		for i in range(0, num_sensors):
			self.sensors.append(Sensor(self.id + "_" + str(i), 85, 115))

		# configure message queue
		self.host = host
		self.link = slink.Link()
		self.packeter = spacketer.Packeter(self.link)
		self.messaging = smessaging.Messaging(self.id, "", self.packeter)
		
		self.transmit_interval = 1
		self.registered_listeners = []

	# start listening on a port
	def addListener(self, port):
		print "Added listener on port %d." % port
		self.link.add_listener(("", port))

	# open outgoing channel on a port
	def addConnector(self, port):
		print "Added connector on port %d." % port
		self.link.add_connector((self.host, port))

	# send a registration message to a potential subscriber
	# to prompt them to initialize themselves and prepare
	# for additional messages.
	def register(self, device_id):
		payload = {"command":"REGISTER", "sensors":[]}
		for s in self.sensors:
			payload["sensors"].append({"name": s.id, "level":self.converter.convert(s), "low": s.low, "high": s.high})
		payload = json.dumps(payload)
		msg = smessage.Message(payload, ttl=60)
		self.messaging.send_message(device_id, msg)
		self.registered_listeners.append(device_id)

	# Send a batch of sensor updates on a scheduled interval
	def update(self):
		while True:
			time.sleep(self.transmit_interval)
			payload = {"command":"UPDATE", "sensors":[]}
			for s in self.sensors:
				payload["sensors"].append({"name": s.id, "level":self.converter.convert(s), "low": s.low, "high": s.high})
			payload = json.dumps(payload)
			msg = smessage.Message(payload, ttl=60)
			for device_id in self.registered_listeners:
				self.messaging.send_message(device_id, msg)		

	def updateLoop(self):
		threading.Thread(target=self.update).start()

	def start(self):
		threading.Thread(target=self.link.loop).start()